"""
Case Type   : gs_dropnode
Case Name   : 减容后执行failover/switchover
Create At   : 2021/4/6
Owner       : opentestcase018
Description :
        1.1主2备，在主机减备1
        2.在主机上检查数据库集群状态
        3.在备机执行switchover
        4.在新主机上刷新配置文件，检查数据库集群状态。
        5.在主机执行stop
        6.在备机进行failover
        7.在备机上刷新配置文件，检查数据库集群状态。
        8.在降备:主机以备机启动
        9.在主机上重启，检查数据库集群状态。
        10.恢复环境
Expect      :
        1.期望:减容成功
        2.期望:期望:1主2备减容为1主1备
        3.期望:切换成功
        4.期望:备升主，主降备
        5.期望:主机stop
        6.期望:切换成功
        7.期望:备升主，主降备
        8.期望:降备成功
        9.期望:备升主，主降备
        10.恢复环境
History     :
        modified by opentestcase018 at 2021-8-5 ;优化同步列表参数还原方式
        modified by opentestcase039 at 2022-3-25 ;优化用例增加建立root互信及清理root互信步骤，
        修改单机环境不执行为非1+2环境不执行
        modified by opentestcase018 at 2022-4-1 ;优化用例 script下无互信工具时解压出来
        modified by opentestcase039 at 2022-10-20 ;优化用例 增加expect中超时时间
"""
import unittest
import os

from testcase.utils.CommonSH import CommonSH
from testcase.utils.Common import Common
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro

LOGGER = Logger()
COMMONSH = CommonSH("PrimaryDbUser")


@unittest.skipIf(1 >= COMMONSH.get_node_num(), '单机环境不执行')
class Gstoolstestcase(unittest.TestCase):
    def setUp(self):
        LOGGER.info(f'-----{os.path.basename(__file__)} start-----')
        self.constant = Constant()
        status = COMMONSH.get_db_cluster_status("detail")
        LOGGER.info(status)
        self.assertTrue("Normal" in status or "Degraded" in status)
        status = COMMONSH.restart_db_cluster()
        LOGGER.info(status)
        status = COMMONSH.get_db_cluster_status("detail")
        LOGGER.info(status)
        self.assertTrue("Normal" in status or "Degraded" in status)
        self.pri_root_node = Node("PrimaryRoot")
        self.user_node = Node("PrimaryDbUser")
        self.s_node1 = Node("Standby1DbUser")
        self.s_node2 = Node("Standby2DbUser")
        self.com_s1 = CommonSH("Standby1DbUser")
        self.com_root = CommonSH("PrimaryRoot")
        self.s_com1 = CommonSH("Standby1DbUser")
        self.s_com2 = CommonSH("Standby2DbUser")
        self.com = Common()
        self.standby_ip_list = [self.s_node1.ssh_host, self.s_node2.ssh_host]
        self.ssh_file = '~/.ssh'

        num = COMMONSH.get_node_num()
        self.assertGreaterEqual(num, 3, "执行失败:节点数量异常，减容不执行")

        LOGGER.info("查询synchronous_standby_names默认值")
        result = COMMONSH.execut_db_sql("show synchronous_standby_names")
        LOGGER.info(f"primary synchronous_standby_names is {result}")
        self.synchronous_standby_names_p = result.strip().splitlines()[-2]
        result = self.s_com1.execut_db_sql("show synchronous_standby_names")
        LOGGER.info(f"s1 synchronous_standby_names is {result}")
        self.synchronous_standby_names_s1 = result.strip().splitlines()[-2]
        result = self.s_com2.execut_db_sql("show synchronous_standby_names")
        LOGGER.info(f"s2 synchronous_standby_names is {result}")
        self.synchronous_standby_names_s2 = result.strip().splitlines()[-2]

        LOGGER.info("-----创建root互信-----")
        result = self.com.get_sh_result(self.pri_root_node,
                                        f"ls {macro.DB_SCRIPT_PATH}")
        if "gs_sshexkey" not in result:
            cmd = f"cd {macro.DB_SCRIPT_PATH}/../; " \
                f"tar -zxvf openGauss-Package-bak*.tar.gz > /dev/null"
            result = self.pri_root_node.sh(cmd).result()
            LOGGER.info(result)
            result = self.com.get_sh_result(self.pri_root_node,
                                            f"ls {macro.DB_SCRIPT_PATH}")
            LOGGER.info(result)
            if "gs_sshexkey" not in result:
                raise Exception("cat not find gs_sshexkey, Please check!")

        self.host_tuple = (self.pri_root_node.ssh_host,
                           self.s_node1.ssh_host,
                           self.s_node2.ssh_host)
        self.params = {'-f': 'test_hosts'}
        self.com_root.exec_gs_sshexkey(macro.DB_SCRIPT_PATH,
                                       *self.host_tuple,
                                       **self.params)

    def test_tool(self):
        LOGGER.info("步骤1:1主2备，执行减容 根据减容和重启提示输入yes")
        result = COMMONSH.execut_db_sql(
            "select count(*) from pg_stat_get_wal_senders();")
        LOGGER.info(result)
        self.assertEqual("2", result.split("\n")[-2].strip())
        execute_cmd = f'''source {macro.DB_ENV_PATH};
                    expect <<EOF
                    set timeout 600
                    spawn gs_dropnode -U {self.user_node.ssh_user} \
                    -G {self.user_node.ssh_user} \
                    -h {self.s_node2.ssh_host}
                    expect "*drop the target node (yes/no)?*"
                    send "yes\\n"
                    expect eof\n''' + '''EOF'''
        LOGGER.info(execute_cmd)
        result = self.user_node.sh(execute_cmd).result()
        LOGGER.info(result)
        self.assertIn("Success to drop the target nodes", result)

        LOGGER.info("步骤2:核对减容成功 剩余1+1")
        result = COMMONSH.execut_db_sql(
            "select count(*) from pg_stat_get_wal_senders();")
        LOGGER.info(result)
        self.assertEqual("1", result.split("\n")[-2].strip())
        status = COMMONSH.get_db_cluster_status("detail")
        LOGGER.info(status)
        self.assertTrue("Normal" in status or "Degraded" in status)

        LOGGER.info("步骤3:执行switchover")
        result = self.com_s1.execute_gsctl("switchover",
                                          "switchover completed")
        LOGGER.info(result)
        self.assertTrue(result)

        LOGGER.info("步骤4:刷新配置文件，检查数据库集群状态")
        result = self.s_node1.sh(
            f"source {macro.DB_ENV_PATH};gs_om -t refreshconf").result()
        LOGGER.info(result)
        self.assertIn("Successfully generated dynamic configuration file",
                      result)
        result = self.com_s1.restart_db_cluster()
        LOGGER.info(result)
        status = self.com_s1.get_db_cluster_status("detail")
        LOGGER.info(status)
        self.assertIn("P Standby Normal", status)
        self.assertIn("S Primary Normal", status)
        self.assertTrue("Normal" in status or "Degraded" in status)

        LOGGER.info("步骤5:在新主机执行stop")
        result = self.com_s1.execute_gsctl("stop", "server stopped")
        LOGGER.info(result)
        self.assertTrue(result)

        LOGGER.info("步骤6:在备机进行failover")
        result = COMMONSH.execute_gsctl("failover", "failover completed")
        LOGGER.info(result)
        self.assertTrue(result)

        LOGGER.info("步骤7:在新主机上刷新配置文件，检查数据库集群状态")
        result = self.user_node.sh(
            f"source {macro.DB_ENV_PATH};gs_om -t refreshconf").result()
        LOGGER.info(result)
        self.assertIn("Successfully generated dynamic configuration file",
                      result)

        LOGGER.info("步骤8:降备:原主机以备机启动")
        result = self.com_s1.execute_gsctl("start", "server started",
                                          "-M standby")
        LOGGER.info(result)
        self.assertTrue(result)

        LOGGER.info("步骤9:在新主机上刷新配置文件，检查数据库集群状态")
        result = self.user_node.sh(
            f"source {macro.DB_ENV_PATH};gs_om -t refreshconf").result()
        LOGGER.info(result)
        self.assertIn("Successfully generated dynamic configuration file",
                      result)
        result = self.com_s1.restart_db_cluster()
        LOGGER.info(result)
        status = COMMONSH.get_db_cluster_status("detail")
        LOGGER.info(status)
        self.assertIn("P Primary Normal", status)
        self.assertIn("S Standby Normal", status)
        self.assertTrue("Normal" in status or "Degraded" in status)

    def tearDown(self):
        LOGGER.info("步骤10:恢复环境")
        status = COMMONSH.get_db_cluster_status("detail")
        LOGGER.info(status)
        result = COMMONSH.execut_db_sql(
            "select count(*) from pg_stat_get_wal_senders();")
        LOGGER.info(result)
        if "2" != result.split("\n")[-2].strip():
            result = self.com_root.exec_expension(f"{self.user_node.ssh_user}",
                                                  f"{self.user_node.ssh_user}",
                                                  f"{self.s_node2.ssh_host}",
                                                  f"{macro.DB_XML_PATH}")
            LOGGER.info(result)
            self.assertTrue(result)

        LOGGER.info("恢复各节点synchronous_standby_names")
        COMMONSH.execute_gsguc("reload",
                               self.constant.GSGUC_SUCCESS_MSG,
                               f"synchronous_standby_names="
                               f"'{self.synchronous_standby_names_p}'",
                               single=True)
        self.s_com1.execute_gsguc("reload",
                                  self.constant.GSGUC_SUCCESS_MSG,
                                  f"synchronous_standby_names="
                                  f"'{self.synchronous_standby_names_s1}'",
                                  single=True)
        self.s_com2.execute_gsguc("reload",
                                  self.constant.GSGUC_SUCCESS_MSG,
                                  f"synchronous_standby_names="
                                  f"'{self.synchronous_standby_names_s2}'",
                                  single=True)

        self.assertTrue("Normal" in status or "Degraded" in status)

        LOGGER.info("-----清理集群节点root互信-----")
        for i in self.standby_ip_list:
            LOGGER.info(f"-----清理备{i}节点互信文件-----")
            rm_cmd1 = f'''ssh {i} <<EOF rm -rf {self.ssh_file}/*\n''' + "EOF"
            LOGGER.info(rm_cmd1)
            rm_res1 = self.pri_root_node.sh(rm_cmd1).result()
            LOGGER.info(rm_res1)

        LOGGER.info(f"-----清理主节点互信文件-----")
        rm_cmd2 = f'''rm -rf {self.ssh_file}/*;ls {self.ssh_file}'''
        LOGGER.info(rm_cmd2)
        rm_res2 = self.pri_root_node.sh(rm_cmd2).result()
        LOGGER.info(rm_res2)
        self.assertEqual('', rm_res2, '清理互信文件失败')
        LOGGER.info(f'-----{os.path.basename(__file__)} end-----')

